import 'dart:async';

import 'package:biometrics/components/common.dart';
import 'package:biometrics/components/controller.dart';
import 'package:biometrics/facedetect_view.dart';
import 'package:biometrics/main.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

enum ErrorType {
  validId("-101", "非法用户ID"),
  notRecordFeature("-202", "该用户人脸未录入"),
  validFeature("-203", "非法人脸特征"),
  emptyDataStore("-301", "人脸数据库为空"),
  matchError("1", "人脸特征匹配失败"),
  unknown("-999", "未知错误"),
  ;

  const ErrorType(this.code, this.message);

  final String code;
  final String message;

  static String errorMessage(dynamic e) {
    for (var v in ErrorType.values) {
      if (v.code == e.toString()) {
        return "错误码 ${v.code}：${v.message}";
      }
    }
    return e.toString();
  }
}

class Method {
  factory Method() => _instance;
  static final Method _instance = Method._internal();
  Method._internal();

  bool? isSafety;
  Database? db;
  Completer databaseCompleter = Completer<Database>();

  final platform = const MethodChannel('example.com/channel');

  static String handleFeature(List<double> list) {
    return list
        .toString()
        .replaceAll('[', '')
        .replaceAll(']', '')
        .replaceAll(',', '');
  }

  static List<double> recoveryFeature(String feature) {
    return feature
        .split(' ')
        .map((e) => double.parse(e))
        .toList()
        .cast<double>();
  }

  int log(String tip, {TipLevel level = TipLevel.info}) {
    return IntentHandlerState.controller?.addTip(tip, level: level) ?? -1;
  }

  void initDatabase() async {
    var path = await getDatabasesPath();
    path = join(path, "face.db");
    log("数据库路径：$path");
    try {
      db = await openDatabase(path, version: 1,
          onCreate: (Database db, int version) async {
        await db.execute(
            'CREATE TABLE IF NOT EXISTS face_features (id INTEGER PRIMARY KEY, feature TEXT)');
      });
    } catch (e) {
      log("打开数据库 $path 失败: $e", level: TipLevel.error);
    }
    if (db == null) {
      return;
    } else {
      log("打开数据库成功，版本：${await db!.getVersion()}", level: TipLevel.success);
      databaseCompleter.complete(db);
    }
  }

  void switchMode({bool? flag}) {
    isSafety = flag ?? !(isSafety ?? true);
    IntentHandlerState.prefs.then((value) async {
      await value.setBool('isSafety', isSafety!);
    });
    if (!(isSafety!) && db == null) {
      initDatabase();
    }
    log("切换模式: ${isSafety! ? "安全模式" : "普通模式"}");
  }

  Future<Map<String, dynamic>?> getIntentAction() async {
    final Map<Object?, Object?>? resultMapRaw =
        await platform.invokeMethod('getIntentAction');
    if (resultMapRaw == null) return null;

    final Map<String, dynamic> resultMap = resultMapRaw.cast<String, dynamic>();

    return resultMap;
  }

  Future<void> setResultAndClose(int resultCode, String resultData) async {
    try {
      log("返回结果并关闭应用");
      recognizer.dispose();
      detector.dispose();
      FacedetectviewState.cap?.dispose();
      db?.close();
      // await Future.delayed(Duration(seconds: 1));
      await platform.invokeMethod('setResultAndClose', {
        'resultCode': resultCode, // RESULT_OK对应-1，需根据调用方需求调整
        'resultData': resultData,
      });
    } on PlatformException catch (e) {
      print("返回结果失败: ${e.message}");
    } finally {}
  }

  Future<int?> writeFaceFeature(List<double> list, int? id) async {
    try {
      if (isSafety != true) {
        return writeFaceFeatureToDB(list, id);
      } else {
        log("写入人脸特征到MicroDroid");
        await platform.invokeMethod('writeFaceFeature', {
          "feature": handleFeature(list),
          "id": id ?? 1,
        });
      }

      return id;
    } catch (e) {
      log("写入人脸特征失败: $e", level: TipLevel.error);
      LOG.error << "writeFaceFeature error: $e";
      return -1;
    }
  }

  Future<int?> matchFaceFeature(List<double> list, {int? id}) async {
    try {
      int? ret;
      if (isSafety == true) {
        log("从MicroDroid中${id == null ? "比对" : "鉴别"}人脸特征");
        ret = await platform.invokeMethod(
            'matchFaceFeature', {"feature": handleFeature(list), "id": id});
      } else {
        ret = await matchFaceFeatureFromDB(list, id: id);
      }
      if (ret.toString() == "1" && id != null) {
        log("鉴别人脸特征失败", level: TipLevel.error);
        return -1;
      } else if (id == null && ret.toString() != "0") {
        log("比对人脸特征成功, id为: $ret", level: TipLevel.success);
      } else if (ErrorType.errorMessage(ret) != ret.toString()) {
        log("${id == null ? "比对" : "鉴别"}人脸特征失败: ${ErrorType.errorMessage(ret)}",
            level: TipLevel.error);
      }
      return ret;
    } catch (e) {
      log("${id == null ? "比对" : "鉴别"}人脸特征失败: ${ErrorType.errorMessage(e)}",
          level: TipLevel.error);
      LOG.error << "matchFaceFeature error: $e";
      return -1;
    }
  }

  Future<int?> clearUserFaceFeatures(int id) async {
    log("删除人脸特征");
    try {
      var ret = isSafety == true
          ? await platform.invokeMethod('clearUserFaceFeatures', {"id": id})
          : await clearUserFaceFeaturesFromDB(id);
      if (ret == 0) {
        log("删除人脸特征失败: $ret");
        return -1;
      } else {
        log("删除人脸特征成功,已删除 $ret 个特征");
        return 0;
      }
    } catch (e) {
      log("删除人脸特征失败: $e", level: TipLevel.error);
      LOG.error << "clearUserFaceFeatures error: $e";
      return -1;
    }
  }

  Future<String> listall() async {
    try {
      if (isSafety == true) {
        return await platform.invokeMethod('listall');
      } else {
        return await listallFromDB();
      }
    } catch (e) {
      LOG.error << "listall error: $e";
      return "";
    }
  }

  Future<int?> writeFaceFeatureToDB(List<double> list, int? id) async {
    await databaseCompleter.future;
    try {
      log("写入人脸特征到本地数据库");
      var ret = await db?.insert(
        'face_features',
        {'id': id ?? 1, 'feature': handleFeature(list)},
        conflictAlgorithm: ConflictAlgorithm.fail,
      );
      if (ret == null) {
        log("写入人脸特征失败", level: TipLevel.error);
        return -1;
      } else {
        log("写入人脸特征成功", level: TipLevel.success);
        return id ?? 1;
      }
    } catch (e) {
      log("写入人脸特征失败: $e", level: TipLevel.error);
      LOG.error << "writeFaceFeature error: $e";
      return -1;
    }
  }

  Future<int?> matchFaceFeatureFromDB(List<double> list, {int? id}) async {
    log("从本地${id == null ? "比对" : "鉴别"}人脸特征");

    await databaseCompleter.future;
    var code = 0;
    try {
      if (id == null) {
        // 比对，需要遍历所有记录
        // 取出全部人脸特征
        var ret = await db?.query('face_features');
        if (ret == null || ret.isEmpty) {
          // 表为空
          code = -301;
        } else {
          try {
            var n = 0;
            var map = ret[0];
            Completer completer = Completer<int>();
            createFuture(Map<String, Object?> map) {
              String feature = map['feature'].toString();
              recognizer.matchFaces(list, [recoveryFeature(feature)]).then(
                (value) {
                  if (value == true) {
                    completer.complete(int.parse(map["id"].toString()));
                  } else {
                    n++;
                    if (n == ret.length) {
                      completer.complete(-202);
                    } else {
                      createFuture(map);
                    }
                  }
                },
              );
            }

            createFuture(map);

            code = await completer.future;
          } catch (e) {
            log("matchFaceFeatureFromeDB执行失败: $e", level: TipLevel.error);
          }
        }
      } else {
        // 鉴别，取出指定的人脸特征
        try {
          var ret = await db
              ?.query('face_features', where: 'id = ?', whereArgs: [id]);
          if (ret == null || ret.isEmpty) {
            // 未查询到
            code = -202;
          } else {
            String feature = ret[0]['feature'].toString();
            code =
                await recognizer.matchFaces(list, [recoveryFeature(feature)]) ==
                        true
                    ? 0
                    : 1;
          }
        } catch (e) {
          log("matchFaceFeatureFromeDB执行失败: $e", level: TipLevel.error);
        }
      }
      return code;
    } catch (e) {
      log("${id == null ? "比对" : "鉴别"}人脸特征失败: $e", level: TipLevel.error);
      LOG.error << "matchFaceFeature error: $e";
      return -1;
    }
  }

  Future<int?> clearUserFaceFeaturesFromDB(int id) async {
    log("从本地数据库中删除人脸特征");
    try {
      if (id == 0) {
        // 清空所有记录
        var ret = await db?.delete('face_features');
        return ret;
      } else {
        var ret =
            await db?.delete('face_features', where: 'id = ?', whereArgs: [id]);
        if (ret == null) {
          log("删除人脸特征失败", level: TipLevel.error);
          return -1;
        } else {
          return 1;
        }
      }
    } catch (e) {
      log("删除人脸特征失败: $e", level: TipLevel.error);
      LOG.error << "clearUserFaceFeatures error: $e";
      return -1;
    }
  }

  Future<String> listallFromDB() async {
    log("从本地数据库中查询所有人脸特征");
    try {
      var ret = await db?.query('face_features');
      if (ret == null || ret.isEmpty) {
        // 表为空
        log("本地数据库为空", level: TipLevel.warning);
        return "";
      } else {
        var str = "";
        for (var map in ret) {
          str += "${map["id"]}: ${map["feature"]}\n";
        }
        return str;
      }
    } catch (e) {
      log("listallFromDB执行失败: $e", level: TipLevel.error);
      return "";
    }
  }
}
